unit TreeUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, Contnrs;

type
  TNode = class
  private
    FInfo: string;
    Children: TObjectList;
  public
    constructor Create(S: string);
    procedure DeleteNode;
    procedure DeleteChildren(const Index: Integer);
    procedure AddChildren(N: TNode);
    function GetChild(Index: Integer): TNode;
    function GetChildrenCount: Integer;
    procedure SaveToStream(Stream: TStream);
    procedure LoadFromStream(Stream: TStream);
    property Info: string read FInfo write FInfo;
  end;

  TDataTree = class
  private
    FRoot: TNode;
    FPath: string;
  public
    constructor Create(S: string);
    procedure GetTree;
    procedure SaveToStream(Stream: TStream);
    procedure LoadFromStream(Stream: TStream);
    property Root: TNode read FRoot write FRoot;
    property Path: string read FPath write FPath;
  end;

implementation

uses MainForm;

constructor TNode.Create(S: string);
begin
  FInfo := S;
  Children := TObjectList.Create;
end;

procedure TNode.DeleteNode;
var
  I: Integer;
begin
  for I := 0 to (Children.Count - 1) do (Children[I] as TNode)
    .DeleteNode;
  Children.Free;
end;

procedure TNode.DeleteChildren(const Index: Integer);
begin (Children[Index] as TNode)
  .DeleteNode; (Children[Index] as TNode)
  .Free;
  Children.Delete(Index);
end;

procedure TNode.AddChildren(N: TNode);
begin
  Children.Add(N);
end;

function TNode.GetChild(Index: Integer): TNode;
begin
  Result := Children[index] as TNode;
end;

function TNode.GetChildrenCount: Integer;
begin
  Result := Children.Count;
end;

procedure TNode.SaveToStream(Stream: TStream);
var
  InfoLength, Count, I: Integer;
begin
  InfoLength := Length(FInfo);
  Stream.Write(InfoLength, SizeOf(Integer));
  Stream.WriteBuffer(FInfo[1], InfoLength * SizeOf(Char));
  Stream.Write(Children.Count, SizeOf(Integer));
  for I := 0 to Children.Count - 1 do (Children[I] as TNode)
    .SaveToStream(Stream);
end;

procedure TNode.LoadFromStream(Stream: TStream);
var
  InfoLength, Count, I: Integer;
  Child: TNode;
  S: string;
begin
  Stream.Read(InfoLength, SizeOf(Integer));
  SetLength(FInfo, InfoLength);
  Stream.ReadBuffer(FInfo[1], InfoLength * SizeOf(Char));
  if Children.Count <> 0 then
    Children.Clear;
  Stream.Read(Count, SizeOf(Integer));
  for I := 0 to Count - 1 do
  begin
    Child := TNode.Create('');
    AddChildren(Child);
    Child.LoadFromStream(Stream);
  end;
end;

constructor TDataTree.Create(S: string);
begin
  Path := S;
end;

procedure GetPathTree(Path: string; Node: TNode);
var
  SearchRec: TSearchRec;
  N: TNode;
  FileExtension: string;
begin
  if FindFirst(Path + '\*.*', faAnyFile - faDirectory, SearchRec) = 0 then
  begin
    repeat
      FileExtension := ExtractFileExt(UpperCase(SearchRec.Name));
      if (SearchRec.Name <> '..') and (SearchRec.Name <> '.') and
        ((FileExtension = '.TXT') or (FileExtension = '.DOC') or
          (FileExtension = '.PDF')) then
      begin
        N := TNode.Create(SearchRec.Name);
        Node.AddChildren(N);
      end;
    until FindNext(SearchRec) <> 0;
    FindClose(SearchRec);
  end;
  if FindFirst(Path + '\*.', faDirectory, SearchRec) = 0 then
  begin
    repeat
      if (SearchRec.Name <> '..') and (SearchRec.Name <> '.') then
      begin
        N := TNode.Create(SearchRec.Name);
        Node.AddChildren(N);
        GetPathTree(Path + '\' + SearchRec.name, N);
      end;
    until FindNext(SearchRec) <> 0;
    FindClose(SearchRec);
  end;
end;

procedure TDataTree.GetTree;
begin
  GetPathTree(Path, Root);
end;

procedure TDataTree.SaveToStream(Stream: TStream);
var
  PathLength: Integer;
begin
  Stream.Position := 0;
  PathLength := Length(FPath);
  Stream.Write(PathLength, SizeOf(Integer));
  Stream.WriteBuffer(FPath[1], PathLength*SizeOf(Char));
  FRoot.SaveToStream(Stream);
end;

procedure TDataTree.LoadFromStream(Stream: TStream);
var
  PathLength: Integer;
begin
  Stream.Position := 0;
  Stream.Read(PathLength, SizeOf(Integer));
  Stream.ReadBuffer(FPath[1], PathLength*SizeOf(Char));
  FRoot := TNode.Create('');
  FRoot.LoadFromStream(Stream);
end;

end.
